/*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 *    SingleAssociatorEnhancer.java
 *    Copyright (C) 2007-2012 University of Waikato, Hamilton, New Zealand
 *
 */

package weka.associations;

import java.util.Collections;
import java.util.Enumeration;
import java.util.Vector;

import weka.core.Capabilities;
import weka.core.Capabilities.Capability;
import weka.core.Option;
import weka.core.OptionHandler;
import weka.core.Utils;

/**
 * Abstract utility class for handling settings common to meta associators that
 * use a single base associator.
 * 
 * @author Eibe Frank (eibe@cs.waikato.ac.nz)
 * @author FracPete (fracpete at waikato dot ac dot nz)
 * @version $Revision$
 */
public abstract class SingleAssociatorEnhancer extends AbstractAssociator implements OptionHandler {

    /** for serialization */
    private static final long serialVersionUID = -3665885256363525164L;

    /** The base associator to use */
    protected Associator m_Associator = new Apriori();

    /**
     * String describing default Associator.
     * 
     * @return default classname
     */
    protected String defaultAssociatorString() {
        return Apriori.class.getName();
    }

    /**
     * Returns an enumeration describing the available options.
     * 
     * @return an enumeration of all the available options.
     */
    @Override
    public Enumeration<Option> listOptions() {
        Vector<Option> result = new Vector<Option>();

        result.addElement(new Option("\tFull name of base associator.\n" + "\t(default: " + defaultAssociatorString() + ")", "W", 1, "-W"));

        if (m_Associator instanceof OptionHandler) {
            result.addElement(new Option("", "", 0, "\nOptions specific to associator " + m_Associator.getClass().getName() + ":"));

            result.addAll(Collections.list(((OptionHandler) m_Associator).listOptions()));
        }

        return result.elements();
    }

    /**
     * Parses a given list of options. Valid options are:
     * <p>
     * 
     * -W classname <br>
     * Specify the full class name of the base associator.
     * <p>
     * 
     * Options after -- are passed to the designated associator.
     * <p>
     * 
     * @param options the list of options as an array of strings
     * @throws Exception if an option is not supported
     */
    @Override
    public void setOptions(String[] options) throws Exception {
        String tmpStr;

        tmpStr = Utils.getOption('W', options);
        if (tmpStr.length() > 0) {
            // This is just to set the associator in case the option
            // parsing fails.
            setAssociator(AbstractAssociator.forName(tmpStr, null));
            setAssociator(AbstractAssociator.forName(tmpStr, Utils.partitionOptions(options)));
        } else {
            // This is just to set the associator in case the option
            // parsing fails.
            setAssociator(AbstractAssociator.forName(defaultAssociatorString(), null));
            setAssociator(AbstractAssociator.forName(defaultAssociatorString(), Utils.partitionOptions(options)));
        }
    }

    /**
     * Gets the current settings of the associator.
     * 
     * @return an array of strings suitable for passing to setOptions
     */
    @Override
    public String[] getOptions() {
        int i;
        Vector<String> result;
        String[] options;

        result = new Vector<String>();

        result.add("-W");
        result.add(getAssociator().getClass().getName());

        if (getAssociator() instanceof OptionHandler) {
            options = ((OptionHandler) getAssociator()).getOptions();
            result.add("--");
            for (i = 0; i < options.length; i++) {
                result.add(options[i]);
            }
        }

        return result.toArray(new String[result.size()]);
    }

    /**
     * Returns the tip text for this property
     * 
     * @return tip text for this property suitable for displaying in the
     *         explorer/experimenter gui
     */
    public String associatorTipText() {
        return "The base associator to be used.";
    }

    /**
     * Set the base associator.
     * 
     * @param value the associator to use.
     */
    public void setAssociator(Associator value) {
        m_Associator = value;
    }

    /**
     * Get the associator used as the base associator.
     * 
     * @return the currently used associator
     */
    public Associator getAssociator() {
        return m_Associator;
    }

    /**
     * Gets the associator specification string, which contains the class name of
     * the associator and any options to the associator
     * 
     * @return the associator string
     */
    protected String getAssociatorSpec() {
        Associator c = getAssociator();
        return c.getClass().getName() + " " + Utils.joinOptions(((OptionHandler) c).getOptions());
    }

    /**
     * Returns default capabilities of the base associator.
     * 
     * @return the capabilities of the base associator
     */
    @Override
    public Capabilities getCapabilities() {
        Capabilities result;

        if (getAssociator() != null) {
            result = getAssociator().getCapabilities();
        } else {
            result = new Capabilities(this);
        }

        // set dependencies
        for (Capability cap : Capability.values()) {
            result.enableDependency(cap);
        }

        result.setOwner(this);

        return result;
    }
}
